package com.digitalchina.dcn.dcss.web.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.digitalchina.dcn.dcss.core.generic.GenericServiceImpl;
import com.digitalchina.dcn.dcss.web.model.Resource;
import com.digitalchina.dcn.dcss.web.dao.ResourceMapper;
import com.digitalchina.dcn.dcss.web.model.Role;
import com.digitalchina.dcn.dcss.web.service.RoleService;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.digitalchina.dcn.dcss.core.generic.GenericDao;
import com.digitalchina.dcn.dcss.web.service.ResourceService;
import org.springframework.util.StringUtils;

/**
 * 权限Service实现类
 *
 * @author StarZou
 * @since 2014年6月10日 下午12:05:03
 */
@Service
public class ResourceServiceImpl extends GenericServiceImpl<Resource, Long> implements ResourceService {

    @Autowired
    private ResourceMapper resourceDao;

    @Autowired
    private RoleService roleService;

    @Override
    public GenericDao<Resource, Long> getDao() {
        return resourceDao;
    }

    @Override
    public List<Resource> selectPermissionsByRoleId(Long roleId) {

        Role role = roleService.selectById(roleId);
        List<Resource> resourceList = new ArrayList<Resource>();
        for (Long resourceId : role.getResourceIds()) {
            Resource resource = resourceDao.selectByPrimaryKey(resourceId);
            if (resource != null && !resourceList.contains(resource)) {
                resourceList.add(resource);
            }
        }
        return resourceList;
    }

    @Override
    public Resource createResource(Resource resource) {
        resourceDao.insert(resource);
        return resourceDao.findByResourceName(resource.getName());
    }

    @Override
    public Resource updateResource(Resource resource) {
        resourceDao.updateByPrimaryKey(resource);
        return resourceDao.selectByPrimaryKey(resource.getId());
    }

    @Override
    public void deleteResource(Long resourceId) {
        resourceDao.deleteByPrimaryKey(resourceId);
        // 删除Role中对该Resource的引用
        for (Role role : roleService.findAll()) {
            if (role.getResourceIds().contains(resourceId)) {
                role.getResourceIds().remove(resourceId);
                roleService.updateRole(role);
            }
        }
    }

    @Override
    public Resource findOne(Long resourceId) {
        return resourceDao.selectByPrimaryKey(resourceId);
    }

    @Override
    public List<Resource> findAll() {
        return resourceDao.findAll();
    }

    @Override
    public Set<String> findPermissions(Set<Long> resourceIds) {
        Set<String> permissions = new HashSet<String>();
        for(Long resourceId : resourceIds) {
            Resource resource = findOne(resourceId);
            if(resource != null && !StringUtils.isEmpty(resource.getPermission())) {
                permissions.add(resource.getPermission());
            }
        }
        return permissions;
    }

    @Override
    public List<Resource> findMenus(Set<String> permissions) {
        List<Resource> allResources = findAll();
        List<Resource> menus = new ArrayList<Resource>();
        for(Resource resource : allResources) {
            if(resource.isRootNode()) {
                continue;
            }
            if(resource.getType() != Resource.ResourceType.menu) {
                continue;
            }
            if(!hasPermission(permissions, resource)) {
                continue;
            }
            menus.add(resource);
        }
        return menus;
    }

    private boolean hasPermission(Set<String> permissions, Resource resource) {
        if(StringUtils.isEmpty(resource.getPermission())) {
            return true;
        }
        for(String permission : permissions) {
            WildcardPermission p1 = new WildcardPermission(permission);
            WildcardPermission p2 = new WildcardPermission(resource.getPermission());
            if(p1.implies(p2) || p2.implies(p1)) {
                return true;
            }
        }
        return false;
    }
}
